/* 
 * File:   NonGenericList.h
 * Author: Enrique Antezana
 *
 * Created on 9 de abril de 2013, 03:17 PM
 */

#ifndef GENERICLIST_H
#define	GENERICLIST_H

#include <iostream>
#include <stdio.h>
#include "NotFoundElementException.h"

template <class T>
class Node {
    T data_;
    Node* nextNode_;
    Node* previousNode_;
public:

    Node(const T& data) {
        data_ = data;
        nextNode_ = NULL;
        previousNode_ = NULL;
    };

    ~Node() {
        printf("NODE DESTRUCTOR ::~NODE()\n");
    }

    void setData(const T& data) {
        data_ = data;
    };

    void setNext(Node* nextNode) {
        nextNode_ = nextNode;
    };

    void setPrevious(Node* previousNode) {
        previousNode_ = previousNode;
    }

    T& getData() {
        return data_;
    };

    Node* getNext() {
        return nextNode_;
    };

    Node* getPrevious() {
        return previousNode_;
    }
};

template <class T>
class GenericList {
private:
    Node<T>* firstNode_;
    int nodeCounter_;

public:

    GenericList();
    void add(const T& data);
    void remove(const T& data);
    int size();
    bool isEmpty();
    T& get(int pos);
    bool contains(const T& data);
};

template <class T>
GenericList<T>::GenericList() {
    firstNode_ = NULL;
    nodeCounter_ = 0;
}

template <class T>
void GenericList<T>::add(const T& data) {
    Node<T> *newNode = new Node<T > (data);

    Node<T> *tempNode = firstNode_;

    if (tempNode != NULL) {
        while (tempNode->getNext() != NULL) {
            tempNode = tempNode->getNext();
        }
        newNode->setPrevious(tempNode);
        tempNode->setNext(newNode);
        nodeCounter_++;

    } else {
        firstNode_ = newNode;
        nodeCounter_ = 1;

    }
}

template <class T>

void GenericList<T>::remove(const T& data) {

    Node<T>* tempNode = firstNode_;
    Node<T>* previousNode = tempNode->getPrevious();
    try {
        if (firstNode_->getData() == data) {
            firstNode_ = firstNode_->getNext();
            delete tempNode;
            nodeCounter_--;
        } else if (nodeCounter_ > 1) {
            if (tempNode->getData() == data) {
                firstNode_ = firstNode_->getNext();
                delete tempNode;
                nodeCounter_--;
            } else {
                do {
                    if (tempNode->getData() == data) {
                        tempNode = tempNode->getNext();
                        previousNode->setNext(tempNode);
                        firstNode_ = previousNode;
                        nodeCounter_--;
                        break;
                    }
                    tempNode = tempNode->getNext();
                    previousNode = tempNode->getPrevious();
                } while (tempNode->getNext() != NULL);

                if (tempNode->getData() == data) {
                    previousNode->setNext(NULL);
                    tempNode = previousNode;
                    nodeCounter_--;
                } else {
                    throw NotFoundElementException();
                }
            }
        }
        if (nodeCounter_ == 1) {
            throw NotFoundElementException();
        }
    } catch (NotFoundElementException& e) {
        printf("%s", e.what());
    }

}

template <class T>

bool GenericList<T>::contains(const T& data) {
    Node<T>* tempNode = firstNode_;

    if (tempNode == NULL)return false;
    if (tempNode->getData() == data) {
        return true;
    } else {
        do {
            if (tempNode->getData() == data) return true;
            tempNode = tempNode->getNext();
        } while (tempNode != NULL);
    }
    return false;
}

template <class T>

T& GenericList<T>::get(int pos) {
    Node<T>* tempNode = firstNode_;
    int counter = 0;
    try {
        if (pos == 0) {
            return firstNode_->getData();
        } else {
            do {
                if (counter == pos) return tempNode->getData();
                tempNode = tempNode->getNext();
                counter++;
            } while (tempNode != NULL);
            if (tempNode == NULL)throw NotFoundElementException();
        }
    } catch (NotFoundElementException& e) {
        printf("%s", e.what());
    }

}

template <class T>

bool GenericList<T>::isEmpty() {
    if (firstNode_ == NULL) {
        return true;
    }
    return false;
}

template <class T>

int GenericList<T>::size() {
    return nodeCounter_;
}

#endif	/* GENERICLIST_H */

